/**
 * Copyright 2024 The coretext Authors. All Rights Reserved.
 */
import { AttributedString, TextUtils, IBlockBuilder, Block } from '@xutils/coretext';
import Stack from '@ohos.util.Stack';
import HashMap from '@ohos.util.HashMap';

const startTag = "#{";
const endTag = "}#";
const groupTags: HashMap<string, string> = (function (): HashMap<string, string> {
  let tags: HashMap<string, string> = new HashMap();
  tags.set("para_begin", "para_end");
  return tags;
})();

export class DefaultBlockMaker implements IBlockBuilder {
  buildBlocks(text: string): Array<Block> {
    const attributedString = new AttributedString(text);
    const list = this.parseData(text);
    // console.log("yangzc", JSON.stringify(list));
    list.forEach((blockData: BlockData) => {
      const block: Block = {
        type: blockData.tag,
        attrs: blockData.attrs,
        body: blockData.body
      };
      attributedString.replace(blockData.start, blockData.end, block);
    })
    return attributedString.build();
  }

  buildTextBlock(content: string): Block {
    return {
      type: "Text",
      body: content
    };
  }

  isContainerBlock(tag: string) {
    return groupTags.hasKey(tag);
  }

  parseData(text: string): Array<BlockData> {
    const items: Array<BlockData> = [];
    var stack: Stack<BlockData> = new Stack();
    for (let i = 0; i < text.length - 1; i++) {
      const flag = text.substring(i, i + 2);
      if (TextUtils.equals(flag, startTag)) {
        if (stack.isEmpty()) {
          var blockData: BlockData = {
            start: i
          };
          items.push(blockData);
        }
        stack.push(blockData);
      } else if (TextUtils.equals(flag, endTag)) {
        const blockData = stack.pop();
        if (stack.isEmpty()) {
          const content = text.substring(blockData.start + 1, i + 1);
          const json = JSON.parse(content);
          blockData.end = i + 2;
          blockData.tag = json["type"];
          blockData.attrs = json;
        }
      }
    }
    return this.mergeGroup(items, text);
  }

  mergeGroup(blocks: Array<BlockData>, text: string): Array<BlockData> {
    const mergeBlocks: Array<BlockData> = [];
    const stack = new Stack<BlockData>();
    let inGroup = false;
    for (let i = 0; i < blocks.length; i++) {
      const block = blocks[i];
      if (groupTags.hasKey(block.tag)) {
        stack.push(block);
        inGroup = true;
      } else if (groupTags.hasValue(block.tag)) {
        const lastBlock = stack.pop();
        if (lastBlock && stack.isEmpty()) {
          // 成对 merge
          mergeBlocks.push({
            start: lastBlock.start,
            end: block.end,
            tag: lastBlock.tag,
            attrs: lastBlock.attrs,
            body: text.substring(lastBlock.end, block.start)
          });
          inGroup = false;
        }
      } else {
        if (!inGroup) {
          mergeBlocks.push(block);
        }
      }
    }
    return mergeBlocks;
  }
}

interface BlockData {
  start: number;
  end?: number;
  tag?: string;
  attrs?: any;
  body?: string;
}